<template>
  <VanField
    :model-value="fieldValue"
    class="city-field"
    is-link
    readonly
    label="省市区"
    placeholder="请选择省市区"
    v-bind="$attrs"
    @click="show = true"
  />
  <VanPopup v-model:show="show" round position="bottom">
    <VanCascader
      v-model="cascaderValue"
      title="请选择省市区"
      :options="options"
      @close="show = false"
      @change="onChange"
      @finish="onFinish"
    />
  </VanPopup>
</template>

<script setup>
import { getProvince, getCity, getCounty } from "@/api/commonApi.js";
import { useRequest } from "@/utils/requestUtils.js";
import { closeToast, showLoadingToast } from "vant";
import { ref, watch, computed, watchEffect } from "vue";

const props = defineProps({
  province: String,
  city: String,
  district: String,
  text: String,
  column: Number,
});

const emits = defineEmits([
  "update:province",
  "update:city",
  "update:district",
  "update:provinceLabel",
  "update:cityLabel",
  "update:districtLabel",
  "update:text",
  "changeText",
]);

const formatData = (data, isLeaf) => {
  data.forEach((item) => {
    item.value = item.dataNo;
    item.text = item.dataName?.split("-").pop();

    if (!isLeaf) {
      item.children = [];
    }
  });
  return data;
};

const cascaderValue = ref(props.district || "");

const show = ref(false);
watch(show, () => {
  if (show.value) {
    switch (props.column) {
      case 1:
        cascaderValue.value = props.province || "";
        break;
      case 2:
        cascaderValue.value = props.city || "";
        break;
      default:
        cascaderValue.value = props.district || "";
    }
  }
});

const { loading: provinceLoading, result: options } = useRequest({
  request: async () => {
    let { data } = await getProvince();
    return formatData(data, props.column === 1);
  },
  initResult: [],
});

const { loading: cityLoading, forceRequest: cityRequest } = useRequest({
  request: async (province) => {
    let { data } = await getCity(province.dataName);
    province.children = formatData(data, props.column === 2);

    return data;
  },
  runNow: false,
});

const { loading: districtLoading, forceRequest: districtRequest } = useRequest({
  request: async (city) => {
    let { data } = await getCounty(city.dataName);
    city.children = formatData(data, true);
    return data;
  },
  runNow: false,
});

const loading = computed(() => {
  return provinceLoading.value || cityLoading.value || districtLoading.value;
});

const fieldValue = computed(() => {
  let value = [props.province, props.city, props.district];
  let len = props.column || 3;
  let text = "";
  let item = {
    children: options.value,
  };
  for (let i = 0; i < len; i++) {
    let list = item?.children || [];
    item = list.find((item) => item.value === value[i]);
  }

  if (item) {
    text = item.dataName;
  }

  return text;
});

watch(fieldValue, () => {
  let value = (fieldValue.value || "").replace(/-/g, "");
  emits("update:text", value);
  emits("changeText", value);
});

// 做初始化
watch(provinceLoading, async () => {
  if (props.province && props.city) {
    let province = options.value.find((item) => item.value === props.province);
    let city = null;

    if (province && props.column !== 1) {
      let citys = await cityRequest(province);
      city = citys?.find((item) => item.value === props.city);
    }

    if (city && props.column !== 2) {
      await districtRequest(city);
    }
  }
});

watchEffect(() => {
  if (loading.value) {
    showLoadingToast("加载中...");
  } else {
    closeToast();
  }
});

// 异步加载
const onChange = async ({ selectedOptions, tabIndex }) => {
  let item = selectedOptions[selectedOptions.length - 1];
  if (item.children?.length === 0) {
    if (tabIndex === 0) {
      cityRequest(item);
    } else if (tabIndex === 1) {
      districtRequest(item);
    }
  }
};

const onFinish = ({ selectedOptions }) => {
  show.value = false;
  selectedOptions.forEach((item, index) => {
    switch (index) {
      case 0:
        emits("update:province", item.value);
        emits("update:provinceLabel", item.text);
        break;
      case 1:
        emits("update:city", item.value);
        emits("update:cityLabel", item.text);
        break;
      case 2:
        emits("update:district", item.value);
        emits("update:districtLabel", item.text);
        break;
    }
  });
};
</script>

<style lang="scss" scoped></style>
